package com.recharge.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.recharge.common.annotation.OperationLogDetail;
import com.recharge.common.domain.PageDO;
import com.recharge.common.enums.ErrorCode;
import com.recharge.common.enums.OperationLogType;
import com.recharge.common.excetion.CustomException;
import com.recharge.common.result.ResultDO;
import com.recharge.common.result.ResultSupport;
import com.recharge.common.util.*;
import com.recharge.core.entity.TransactionEntity;
import com.recharge.core.entity.WithdrawEntity;
import com.recharge.core.mapper.WithdrawMapper;
import com.recharge.domain.query.WithdrawQueryDO;
import com.recharge.domain.vo.*;
import com.recharge.service.MerchantAccountService;
import com.recharge.service.MerchantService;
import com.recharge.service.TransactionService;
import com.recharge.service.WithdrawService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author reagan
 * @since 2020-08-19
 */
@Service
public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, WithdrawEntity> implements WithdrawService {

    @Value("${node.name}")
    private Integer nodeName;

    @Autowired
    MerchantAccountService merchantAccountService;
    @Autowired
    MerchantService merchantService;
    @Autowired
    TransactionService transactionService;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    WithdrawMapper withdrawMapper;
    @Autowired
    RedissonClient redissonClient;

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Override
    public ResultDO add(WithdrawDO domain) {

        WithdrawEntity entity = new WithdrawEntity();

        ResultDO result = BeanUtilsExtends.copy(entity, domain);
        // 判断是否复制成功
        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        boolean res;
        try {
            res = this.save(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        //判断r的值是否小于0.如果小于0 就代表添加失败
        if (!res) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR);
            logger.debug("error code：" + ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR.getCode() + " msg" + ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR.getMsg());
            return result;
        }

        return result;
    }

    @Override
    public ResultDO edit(WithdrawDO domain) {

        WithdrawEntity entity = new WithdrawEntity();

        ResultDO result = BeanUtilsExtends.copy(entity, domain);
        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        boolean res = false;
        try {
            res = this.updateById(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        //判断r的值是否小于0.如果小于0 就代表添加失败
        if (!res) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_EDIT_ERROR);
            logger.debug("error code：" + ErrorCode.WITHDRAWAL_RECORD_EDIT_ERROR.getCode() + " msg" + ErrorCode.WITHDRAWAL_RECORD_EDIT_ERROR.getMsg());
            return result;
        }

        return result;
    }

    @Override
    public ResultDO get(String id) {

        ResultDO result = new ResultSupport();
        WithdrawEntity entity = null;

        try {
            entity = this.getById(id);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        WithdrawDO domain = getDomain(entity);

        result.setModel(ResultDO.FIRST_MODEL_KEY, domain);

        return result;
    }

    @Override
    public ResultDO remove(String id) {

        ResultDO result = new ResultSupport();
        WithdrawEntity entity = new WithdrawEntity();

        entity.setId(id);
        entity.setIsDelete(-1);

        boolean res = false;
        try {
            res = this.updateById(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        //判断r的值是否小于0.如果小于0 就代表添加失败
        if (!res) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_DELETE_ERROR);
            logger.debug("error code：" + ErrorCode.WITHDRAWAL_RECORD_DELETE_ERROR.getCode() + " msg" + ErrorCode.WITHDRAWAL_RECORD_DELETE_ERROR.getMsg());
            return result;
        }

        return result;
    }

    @Override
    public ResultDO find(WithdrawQueryDO query) {
        // 创建实体类
        WithdrawEntity entity = new WithdrawEntity();
        // 拷贝数据
        ResultDO result = BeanUtilsExtends.copy(entity, query);

        //判断是否拷贝成功
        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        // 创建查询器
        QueryWrapper<WithdrawEntity> wrapper = new QueryWrapper<>(entity);
        // 条件:开始时间
        if (!TemplateUtils.isEmpty(query.getStartTime())) {
            wrapper.ge("applicant_date", query.getStartTime());
        }
        // 条件:结束时间
        if (!TemplateUtils.isEmpty(query.getEndTime())) {
            wrapper.lt("applicant_date", query.getEndTime());
        }
        // 条件:提现金额
        if (!TemplateUtils.isEmpty(query.getAmount())) {
            wrapper.eq("amount", query.getAmount());
        }
        // 条件:商户ID
        if (!TemplateUtils.isEmpty(query.getMerchantId())) {
            wrapper.eq("merchant_id", query.getMerchantId());
        }
        // 条件:状态
        if (!TemplateUtils.isEmpty(query.getStatus())) {
            wrapper.eq("status", query.getStatus());
        }

        wrapper.eq("is_delete", Constant.IS_DELETE_FALSE);
        wrapper.orderByDesc("applicant_date");
        Page<WithdrawEntity> page = new Page<>(query.getCurrentPage(), query.getPageSize());

        IPage<WithdrawEntity> iPage;
        try {
            // 分页查询
            iPage = baseMapper.selectPage(page, wrapper);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        // 获取查询信息
        List<WithdrawDO> doList = getDomainList(iPage.getRecords());
        PageDO<WithdrawDO> pageDO = new PageDO<>();

        // 设置分页信息
        pageDO.setCurrentPage(iPage.getCurrent());
        pageDO.setPageCount(iPage.getPages());
        pageDO.setPageSize(iPage.getSize());
        pageDO.setRowCount(iPage.getTotal());
        pageDO.setData(doList);

        result.setModel(ResultDO.FIRST_MODEL_KEY, pageDO);
        return result;
    }

    /**
     * <h1>描述: 提现申请</h1>
     *
     * @author kui
     * @date 2020/8/24 16:51
     */
    @OperationLogDetail(detail = "提现申请", operationType = OperationLogType.ADD)
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public ResultDO applyWithdraw(WithdrawDO domain, String userName) {

        WithdrawEntity entity = new WithdrawEntity();
        ResultDO result = BeanUtilsExtends.copy(entity, domain);
        if (!result.isSuccess()) {
            return result;
        }

        /*
         * 查询添加所需信息
         */
        MerchantAccountDO merchantAccountDO = null;
        MerchantDO merchantDO = null;
        UserLoginDO userLoginDO = null;
        int count = 0;
        try {
            // 代理商ID
            String merchantId = domain.getMerchantId();

            merchantAccountDO = (MerchantAccountDO) merchantAccountService.get(merchantId).getModel(ResultDO.FIRST_MODEL_KEY);
            merchantDO = (MerchantDO) merchantService.get(merchantId).getModel(ResultDO.FIRST_MODEL_KEY);
//            userLoginDO = (UserLoginDO) redisUtil.get(Constant.USER + userName);
            count = withdrawMapper.selectCount(merchantId, Constant.WITHDRAW_VERIFICATION_UNKNOWN);

        } catch (Exception e) {
            logger.debug("获取代理商信息异常");
        }
        if (merchantAccountDO == null
                || merchantDO == null) {
            logger.debug("获取代理商信息失败");
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PARAM_GET_ERROR);
            return result;
        }

        if (count != 0) {
            logger.debug("有未审核提现申请,无法再次申请");
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.TEMPLATE_PARAM_TEMPLATE_ERROR);
            return result;
        }

        if (merchantAccountDO.getBalance().compareTo(domain.getAmount()) < 0) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.API_USER_BALANCE_STATUS_ERROR);
            return result;
        }

        // 真实姓名
//        String realName = "";
//        UserDetailDO userDetailDO = userLoginDO.getUserDetailDO();
//        if (userDetailDO != null && userDetailDO.getRealName() != null) {
//            realName = userDetailDO.getRealName();
//        }

        /*
            添加提现记录
         */
        //商户名称
        entity.setMerchantName(merchantDO.getMerchantName());
        //审核状态: 0.待审核 1.审核通过 2.审核未通过 3.已打款 4.已退款 5.取消
        entity.setStatus(Constant.DEPOSIT_VERIFICATION_UNKNOWN);
        //交易号
        String transactionNo = SnowflakeIdWorker.getNo();
        entity.setTransactionNo(transactionNo);
        //提现记录号
        entity.setWithdrawNo(SnowflakeIdWorker.getNo());
        //申请人
        entity.setApplicant(userName);

        /*
            添加交易记录
         */
        TransactionDO transactionDO = new TransactionDO();
        // 交易号
        transactionDO.setTransactionNo(transactionNo);
        // 商户号
        transactionDO.setMerchantNo(merchantDO.getMerchantNo());
        // 商家账户号
        transactionDO.setAccountNo(merchantAccountDO.getAccountNo());
        // 类型: 1.存款 2.提现 3.商品订单 4.退款
        transactionDO.setType(Constant.TRANSACTION_TYPE_2);
        // 金额
        transactionDO.setAmount(domain.getAmount());
        // 1.收入 2.支出
        transactionDO.setAmountType(Constant.EXPEND);
        // 余额
//        transactionDO.setBalance(merchantAccountDO.getBalance());
        // 提现单号
        transactionDO.setIdentifierNo(entity.getWithdrawNo());
        // 设置节点名称
        transactionDO.setNodeName(nodeName);
        // 交易状态
        transactionDO.setStatus(Constant.TRANSACTION_STATUS_2);

        boolean save;

        try {
            result = transactionService.add(transactionDO);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR);
            logger.debug("添加交易记录失败");
            return result;
        }
        if (!result.isSuccess()) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR);
            logger.debug("添加提现记录失败");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }

        try {
            TransactionDO resultModel = (TransactionDO) result.getModel(ResultDO.FIRST_MODEL_KEY);
            entity.setTransactionId(resultModel.getId());
            save = this.save(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR);
            logger.debug("添加提现申请记录失败");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }
        if (!save) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.WITHDRAWAL_RECORD_ADD_ERROR);
            logger.debug("添加提现记录失败");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }

        result.setModel(ResultDO.FIRST_MODEL_KEY, entity);
        return result;
    }

    /**
     * <h1>描述: 提现审核</h1>
     *
     * @param domain
     * @return
     */
    @Override
    @OperationLogDetail(detail = "提现审核", operationType = OperationLogType.UPDATE)
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ResultDO verifyWithdraw(WithdrawDO domain, String userName) {
        ResultDO result = new ResultSupport();

        /*
         * 获取参数
         */
        WithdrawEntity entity = null;
//        UserLoginDO userLoginDO = null;
        MerchantAccountDO merchantAccountDO = null;
        try {
            entity = baseMapper.selectById(domain.getId());
            if (entity == null) {
                result.setSuccess(false);
                result.setErrorCode(ErrorCode.PARAM_GET_ERROR);
                logger.debug("获取提现申请记录失败");
                return result;
            }
//            userLoginDO = (UserLoginDO) redisUtil.get(Constant.USER + userName);
            merchantAccountDO = (MerchantAccountDO) merchantAccountService.get(entity.getMerchantId()).getModel(ResultDO.FIRST_MODEL_KEY);
        } catch (Exception e) {
            logger.debug("获取参数异常" + e.getMessage());
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            return result;
        }

        if (merchantAccountDO == null) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PARAM_GET_ERROR);
            logger.debug("获取用户或商户参数失败");
            return result;
        }

        if (entity.getStatus() != Constant.WITHDRAW_VERIFICATION_UNKNOWN) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.VERIFICATION_STATUS_ERROR);
            logger.debug("不是待审核申请,无法审核");
            return result;
        }

        // 真实姓名
//        String realName = "";
//        UserDetailDO userDetailDO = userLoginDO.getUserDetailDO();
//        if (userDetailDO != null) {
//            realName = userDetailDO.getRealName();
//        }

        /*
         * 审核提现
         */
        WithdrawEntity withdrawEntity = new WithdrawEntity();
        TransactionEntity transactionEntity = new TransactionEntity();

        if (domain.getStatus() == Constant.WITHDRAW_VERIFICATION_SUCCESS) { // 审核通过

            if (merchantAccountDO.getBalance() == null || merchantAccountDO.getBalance() < entity.getAmount()) {
                result.setSuccess(false);
                result.setErrorCode(ErrorCode.VERIFICATION_FAIL);
                logger.debug("商户余额不足,无法提现");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return result;
            }

            // 1.修改余额
            result = merchantAccountService.editBalance(entity.getMerchantId(), -entity.getAmount());
            if (!result.isSuccess()) {
                logger.debug("修改余额失败");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return result;
            }

            Long before = (Long) result.getModel(ResultDO.FIRST_MODEL_KEY);
            Long after = (Long) result.getModel(ResultDO.SECOND_MODEL_KEY);

            // 设置提现记录状态
            withdrawEntity.setStatus(Constant.WITHDRAW_VERIFICATION_SUCCESS);
            withdrawEntity.setBeforeBalance(before);
            withdrawEntity.setAfterBalance(after);

            // 设置交易流水状态
            transactionEntity.setStatus(Constant.TRANSACTION_STATUS_1);
            transactionEntity.setBeforeBalance(before);
            transactionEntity.setBalance(after);
        } else { // 审核驳回
            withdrawEntity.setStatus(Constant.WITHDRAW_VERIFICATION_FAIL);
            transactionEntity.setStatus(Constant.TRANSACTION_STATUS_0);
        }

        withdrawEntity.setId(entity.getId());
        withdrawEntity.setSerialNumber(domain.getSerialNumber());
        withdrawEntity.setBankAccount(entity.getBankAccount());
        withdrawEntity.setBankAccountType(entity.getBankAccountType());
        withdrawEntity.setBankName(entity.getBankName());
        withdrawEntity.setChecker(userName);
        withdrawEntity.setCheckerDate(new Date());

        transactionEntity.setId(entity.getTransactionId());

        /*
         * 修改交易记录
         */
        boolean updateTransaction = false;
        try {
            updateTransaction = transactionService.updateById(transactionEntity);
        } catch (Exception e) {
            logger.info(e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.VERIFICATION_FAIL);
        }
        if (!updateTransaction) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.VERIFICATION_FAIL);
            logger.debug("修改提现记录失败");
            return result;
        }

        /*
         * 修改提现
         */
        int updateWithdraw = 0;

        RLock lock = redissonClient.getLock("LOCK_DEPOSIT" + domain.getId());
        try {
            if (lock.tryLock(30, TimeUnit.SECONDS)) {
                entity = baseMapper.selectById(domain.getId());
                if (entity == null || entity.getStatus() != Constant.WITHDRAW_VERIFICATION_UNKNOWN) {
                    result.setErrorCode(ErrorCode.VERIFICATION_STATUS_ERROR);
                    result.setSuccess(false);
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return result;
                }
                updateWithdraw = baseMapper.updateById(withdrawEntity);
            }
        } catch (Exception e) {
            logger.info(e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.VERIFICATION_FAIL);
            return result;
        } finally {
            lock.unlock();
        }

//        int updateWithdraw = 0;
//        boolean updateTransaction = false;
//        try {
//            updateWithdraw = baseMapper.updateById(withdrawEntity);
//            updateTransaction = transactionService.updateById(transactionEntity);
//        } catch (Exception e) {
//            logger.debug(e.getMessage());
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//        }
        if (updateWithdraw <= 0) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.VERIFICATION_FAIL);
            logger.debug("修改提现状态失败");
            return result;
        }
        return result;
    }

    private WithdrawDO getDomain(WithdrawEntity entity) {

        //判断房源对象是否为空，为空就返回 空，不为空就进行下面的代码
        if (entity == null) {
            return null;
        }
        WithdrawDO domain = new WithdrawDO();
        domain = BeanUtilsExtends.copyProperties(domain, entity) ? domain : null;

        //判断拷贝数据到Dto对象是否成功，如果成功则返回domian，如果不成功就返回空
        return domain;
    }

    private List<WithdrawDO> getDomainList(List<WithdrawEntity> list) {
        //创建一个名为dolist的房源do类型的 list集合
        List<WithdrawDO> doList = new ArrayList<WithdrawDO>();

        //判断传入的list的集合的size是否大于0
        if (list.size() > 0) {
            //大于0是，遍历list，创建do类型的对象 调用getdomain方法
            for (WithdrawEntity entity : list) {

                WithdrawDO domain = this.getDomain(entity);

                //判断得到的domain 是否为空 不为空 就往dolist集合里面添加domian 为空就返回空
                if (domain == null) {
                    return null;
                }
                doList.add(domain);
            }
        } else {
            return null;
        }
        return doList;
    }

//    @Transactional
//    public ResultDO applyWithdrawInfo(TransactionEntity transactionEntity, WithdrawEntity entity) {
//        ResultSupport result = new ResultSupport();
//        //transactionEntity = transactionService.insert(transactionEntity);
//        if (transactionEntity.getId() == null) {
//            throw new CustomException(500, "添加交易记录失败");
//        }
//
//        //交易ID
//        entity.setTransactionId(transactionEntity.getId());
//        int insert = baseMapper.insert(entity);
//        if (insert <= 0) {
//            throw new CustomException(500, "添加提现申请失败");
//        }
//        /*
//            修改映射ID
//          */
//        // 根据类型可以是 订单号 存款单号 退款单号
//        transactionEntity.setIdentifierNo(entity.getWithdrawNo());
//
//        boolean b = transactionService.updateById(transactionEntity);
//        if (!b) {
//            throw new CustomException(500, "修改交易记录失败");
//        }
//
//        result.setSuccess(true);
//        return result;
//    }
//
//    @Transactional
//    public ResultDO exampleWithdrawInfo(WithdrawEntity entity, TransactionEntity transactionEntity) {
//        ResultSupport result = new ResultSupport();
//        boolean updateWithdraw = this.updateById(entity);
//        if (!updateWithdraw) {
//            throw new CustomException(500, "修改提现记录失败");
//        }
//        boolean updateTransaction = transactionService.updateById(transactionEntity);
//        if (updateTransaction) {
//            throw new CustomException(500, "修改交易记录失败");
//        }
//        result.setSuccess(true);
//        return result;
//    }

}
